/**
 * Created by ebalmes Oct 5, 2009 8:46:56 AM
 * 
 */
package model;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import listeners.IDataModelListener;
import model.interfaces.IDataModel;
import model.types.MedEx;
import model.types.Patient;
import dao.UseFilesAsDataBase;
import dao.interfaces.DataBase;
import exceptions.DataException;

public class DataModel implements IDataModel
{
  /**
   * The singleton instance.
   */
  private static DataModel dataModel;
  private List<Patient> data = new ArrayList<Patient>();
  private List<IDataModelListener> listeners = new ArrayList<IDataModelListener>();
  private int selectedTajNumber;
  private final DataBase db;
  private static Logger logger = Logger.getLogger(DataModel.class.getName());

  /**
   * Singleton contructor.
   */
  private DataModel() {
    data = new ArrayList<Patient>();
    db = new UseFilesAsDataBase();
  }

  /**
   * Returns the Singleton instance of the DataModel.
   * 
   * @return the datamodel instance
   */
  public static DataModel getInstance() {
    if (dataModel == null) {
      dataModel = new DataModel();
    }
    return dataModel;
  }

  @Override
  public void addDataModelListener(IDataModelListener l) {
    if (!listeners.contains(l)) {
      listeners.add(l);
    }
  }

  @Override
  public void addMedEx(MedEx medEx, Patient patient) {
    patient.addMedEx(medEx);
  }

  @Override
  public void addPatient(Patient patient) throws DataException {
    if (!data.contains(patient)) {
      data.add(patient);
      return;
    }
    logger.log(Level.SEVERE, "The patient (" + patient.getName()
        + ") is already exist in the database!");
    throw new DataException("Patient is already exists in the database!");
  }

  @Override
  public void addPatients(List<Patient> patients) {
    data.addAll(patients);
  }

  @Override
  public void fireDataModelCleaned() {
    for(IDataModelListener l : listeners) {
      l.dataModelCleaned();
    }
  }

  @Override
  public void fireDataModelUpdated() {
    for(IDataModelListener l : listeners) {
      l.dataModelUpdated();
    }
  }

  @Override
  public List<MedEx> getMedex4PatientBetweenDates(int tajNumber,
      Date startDate, Date endDate) throws DataException {
    // Patient patient = getPatientByTajNumber(tajNumber);
    // List<MedEx> medExList = patient.getMedExList();
    // List<MedEx> result = new ArrayList<MedEx>();
    // for (MedEx m : medExList) {
    // if (m.getMedExDate().compareTo(startDate) > 0 &&
    // m.getMedExDate().compareTo(endDate) < 0) {
    // result.add(m);
    // }
    // }
    // return result;
    return null;
  }

  @Override
  public Patient getPatientByTajNumber(int tajNumber) throws DataException {
    for(Patient p : data) {
      if (p.getTajNumber() == tajNumber) {
        return p;
      }
    }
    logger.log(Level.SEVERE, "The patient (" + tajNumber
        + ") doesn't exist in the database!");
    throw new DataException("The patient doesn't exist in the database!");
  }

  @Override
  public List<Patient> getPatients(String searchString) {
    List<Patient> resultList = new ArrayList<Patient>();
    Integer tajNumber = null;
    for(Patient p : data) {
      tajNumber = p.getTajNumber();
      if (p.getName().indexOf(searchString) != -1
          || tajNumber.toString().indexOf(searchString) != -1) {
        if (!resultList.contains(p)) {
          resultList.add(p);
        }
      }
    }
    return resultList;
  }

  @Override
  public void removeDataModelListener(IDataModelListener l) {
    if (listeners.contains(l)) {
      listeners.remove(l);
    }
  }

  @Override
  public void removeMedEx(int medExId, Patient patient) throws DataException {
    List<MedEx> list = patient.getMedExList();
    MedEx medEx2Remove = null;
    for(MedEx m : list) {
      if (m.getMedExId() == medExId) {
        medEx2Remove = m;
      }
    }
    if (medEx2Remove != null) {
      list.remove(medEx2Remove);
    } else {
      logger.log(Level.SEVERE, "The medical examination (" + medExId
          + ") doesn't exist in the database!");
      throw new DataException("There is no Medical Examination with this ID!");
    }
  }

  @Override
  public void removePatient(int tajNumber) throws DataException {
    Patient patient2Remove = getPatientByTajNumber(tajNumber);
    data.remove(patient2Remove);
  }

  @Override
  public void updateMedEx(int medExId, MedEx updatedMedEx) throws DataException {
    MedEx medEx = getMedexById(medExId);
    medEx.setDescription(updatedMedEx.getDescription());
    medEx.setMedExDate(updatedMedEx.getMedExDate());
  }

  public MedEx getMedexById(int medExId) throws DataException {
    List<MedEx> medExList = new ArrayList<MedEx>();
    for(Patient p : data) {
      medExList = p.getMedExList();
      for(MedEx m : medExList) {
        if (m.getMedExId() == medExId) {
          return m;
        }
      }
    }
    logger.log(Level.SEVERE, "There is no Medical Examination with the ID: "
        + medExId);
    throw new DataException("There is no Medical Examination with this ID!");
  }

  @Override
  public void updatePatient(int tajNumber, Patient updatedPatient)
      throws DataException {
    Patient patient = getPatientByTajNumber(tajNumber);
    patient.setName(updatedPatient.getName());
    patient.setDateOfBirth(updatedPatient.getDateOfBirth());
    patient.setAddress(updatedPatient.getAddress());
    patient.setMothersName(updatedPatient.getMothersName());
    patient.setPlaceOfBirth(updatedPatient.getPlaceOfBirth());
  }

  @Override
  public void clearModel() {
    data.clear();
  }

  @Override
  public Patient getSelectedPatient() throws DataException {
    return getPatientByTajNumber(selectedTajNumber);
  }

  @Override
  public void setSelectedPatient(int tajNumber) throws DataException {
    selectedTajNumber = tajNumber;
    firePatientSelected();
  }

  private void firePatientSelected() throws DataException {
    for(IDataModelListener l : listeners) {
      l.patientSelected();
    }
  }

  public void save() throws IOException {
    db.saveData(data);
  }

  public void load() throws IOException, ClassNotFoundException {
    data = db.getData();
  }
}
